
#region Imports

using System;
using System.Collections.Generic;
using System.Text;

using Justa.Model;

#endregion

namespace Justa.Common
{
    /// <summary>
    /// 
    /// </summary>
    ///  
    /// <author>Abel Perez (java.aperez@gmail.com)</author>
    /// 
    public class ExceptionFormatter
    {
        /// <summary>
        /// 
        /// </summary>
        /// 
        /// <param name="exception"></param>
        /// 
        /// <returns></returns>
        /// 
        public static CapturedExceptionCollection<CapturedException> CaptureException(Exception exception)
        {
            return CaptureException(exception, null);
        }

        /// <summary>
        /// This operation recursively calls itself if the specified 
        /// exception has inner exceptions.
        /// </summary>
        /// 
        /// <param name="exception"></param>
        /// <param name="outerException"></param>
        /// 
        /// <returns></returns>
        /// 
        public static CapturedExceptionCollection<CapturedException> CaptureException(Exception exception, Exception outerException)
        {
            if (exception == null)
            {
                throw new ArgumentNullException("exception");
            }

            CapturedExceptionCollection<CapturedException> result = new CapturedExceptionCollection<CapturedException>();
            CapturedException item = new CapturedException(exception);
            result.Add(item);

            if (outerException == null)
            {
                item.OuterException = true;
            }

            System.Exception inner = exception.InnerException;

            if (inner != null)
            {
                result.Merge(CaptureException(inner, exception).GetEntities());
            }

            return result;
        }
        
        /// <summary>
        /// 
        /// </summary>
        /// 
        /// <param name="exception"></param>
        /// 
        /// <returns></returns>
        /// 
        public static string Format(Exception exception)
        {
            CapturedExceptionCollection<CapturedException> exceptions = CaptureException(exception);
            StringBuilder result = new StringBuilder();
            result.Append(FormatExceptionHeader(exceptions));
            string heading = string.Empty;

            foreach (CapturedException capturedException in exceptions)
            {
                if (capturedException.OuterException == true)
                {
                    heading = string.Format("Outer Exception: {0}", capturedException.ExceptionType);
                }
                else
                {
                    heading = string.Format("Inner Exception: {0}", capturedException.ExceptionType);
                }

                result.AppendLine(heading);
                result.AppendLine(new string('-', heading.Length));
                result.Append(FormatException(capturedException));
            }

            return result.ToString();
        }

        /// <remarks />
        /// 
        private static string FormatException(CapturedException exception)
        {
            return new StringBuilder()
                .AppendFormat("Type: {0} \n", exception.ExceptionType)
                .AppendFormat("Message: {0} \n", exception.ExceptionMessage)
                .AppendFormat("Source: {0} \n", exception.ExceptionSource)
                .AppendFormat("StackTrace: {0} \n\n", exception.StackTrace).ToString();
        }

        /// <remarks />
        /// 
        private static string FormatExceptionHeader(CapturedExceptionCollection<CapturedException> exceptions)
        {
            return new StringBuilder()
                .AppendFormat("Time: {0} \n", exceptions.TimeStamp)
                .AppendFormat("Machine: {0} \n", exceptions.MachineName)
                .AppendFormat("Windows Identity: {0} \n", exceptions.WindowsIdentity)
                .AppendFormat("Assembly: {0} \n", exceptions.AssemblyFullName)
                .AppendFormat("App Domain: {0} \n", exceptions.AppDomainName)
                .AppendLine(new String('-', 80)).AppendLine().ToString();
        }
    }
}